Desenvolvimento para Dispositivos Móveis
Aula 06
Prof. Dr. Raulcézar Alves
raulcezar@gmail.com

Google - Firebase

É uma plataforma de backend para construção de aplicações Web, Android e iOS. Ela oferece: base de dados de tempo-real, diferentes APIs, serviço de autenticação e hospedagem. Então, seu App pode se conectar a um projeto no Firebase para usar os serviços citados. O Android Studio facilita essa integração.

Google - Firebase

  • Real-time database: suporta dados JSON como forma de estruturar os dados, e todos os usuários conectados a ele recebem atualizações após cada mudança.
  • Authentication: pode−se usar diferentes formas de autenticação na sua aplicação, como: anônimo, usuário-senha, e contas de redes sociais.
  • Hosting: o backend da aplicação pode ser hospedado nos servidores Firebase, inclusive com conexão segura.

Google - Firebase

    Vantagens:
  • Fácil e amigável de usar, sem configurações complexas.
  • Os dados são de tempo-real, o que significa que cada mudança automaticamente atualiza as informações dos clientes conectados.
  • Oferece um painel de controle simples para serviços.
  • Existem diversos serviços úteis disponíveis.
    Desvantagens:
  • O plano grátis é limitado a 50 conexões e 100MB de armazenamento.

Google - Firebase

Site: é necessário uma conta google

Google - Firebase

Console de um projeto: serviços disponíveis

Google - Firebase

Autenticação>>usuários: mostra os usuários cadastrados para logar no seu App.

Google - Firebase

Autenticação>>método de login: tipos de autenticação. Pode ser: anônimo, usuário-senha com autocadastro direto no seu app, ou por conta de redes sociais.

Google - Firebase

Autenticação>>modelos: verificações de cadastro.

Google - Firebase

Autenticação>>modelos: verificações de cadastro.

Google - Firebase

Autenticação>>modelos: verificações de cadastro.

Google - Firebase

Autenticação>>modelos: verificações de cadastro.

Google - Firebase

Autenticação>>modelos: verificações de cadastro.

Google - Firebase

Database: oferece 2 sistemas.
Realtime DatabaseCloud Firestore
Armazena dados como uma grande árvore JSON.Armazena dados em documentos organizados em coleções.
Suporte off-line para clientes móveis apenas no iOS e Android.Suporte off-line para clientes iOS, Android e da Web.
Consultas avançadas com funcionalidade limitada de classificação e filtragem.Consultas indexadas com classificação e filtragem compostas.
Operações básicas de gravação e transação.Operações em lote atômicas de gravação e transação.
É um produto maduro.Está na versão Beta.

Google - Firebase

Database: armazenamento de dados remoto.

Google - Firebase

Database>>dados: mostra/adiciona/remove dados da estrutura.

Google - Firebase

Database>>regras: permissões de leitura e escrita na estrutura de dados.

Google - Firebase

Database>>backups: por padrão na versão free não há.

Google - Firebase

Database>>uso: estatísticas de dispositivos conectados, espaço de armazenamento, etc.

Google - Firebase

Storage: armazenamento de mídias e dados não estruturados.

Google - Firebase

Hosting: hospedagem de aplicações web.

Google - Firebase

Function: rodar funções de backend com JS no servidor Firebase.

Google - Firebase

ML Kit: algoritmos de Machine Learning (IA) para: reconhecimento de texto, detecção de rostos, leitura de códigos de barras, identificação de imagens e reconhecimento de pontos de referência. Algoritmos já treinados, seu App envia o dado (imagem, texto, etc) e o serviço Firebase retorna a resposta.

Criação de App com autenticação no Firebase

Criação de App com autenticação no Firebase

    pré-requisitos
  • dispositivo com versão 4.0 ou superior
  • Google Play Services 11.0.4 ou superior
  • Android Studio versão 1.5 ou superior
  • usar Firebase Assistant do Android Studio
  • se for usar emulador, certifique-se de criá-lo usando uma imagem que possua a Play Store instalada

Crie um novo projeto no Android Studio

Crie um novo projeto no Android Studio

Crie um novo projeto no Android Studio

Crie um novo projeto no Android Studio

Selecione uma Activity do tipo login. Isso criará toda a estrutura para logar, deslocar e autocadastrar um usuário no Firebase futuramente.

Crie um novo projeto no Android Studio

Selecione uma Activity do tipo login. Isso criará toda a estrutura para logar, deslocar e autocadastrar um usuário no Firebase futuramente.

Depois disso, vá no menu Tools > Firebase e o Firebase Assistant se abrirá, com diversas opções.

Escolha a Authentication.

O método de autenticação será por e-mail e senha. O primeiro passo é conectar seu app ao Firebase, clicando no botão "Connect to Firebase".

Será necessário se conectar a sua conta google. Um site será aberto para logar e dar as permissões.

Será necessário se conectar a sua conta google. Um site será aberto para logar e dar as permissões.

Se tudo aconteceu corretamente, você deve ver a tela de sucesso informando que você já pode voltar ao Android Studio.

Quando voltar ao Android Studio, configure um novo Firebase Project, que basicamente é o seu projeto de backend. Use o mesmo nome do seu projeto e selecione a região Brazil.

Algumas dependências serão baixadas. Depois disso, o Firebase mostrará que está conectado ao Android Studio. Agora adicione a autenticação ao App.

Mais dependências serão instaladas. Aceite as modificações.

Em caso de warnings modifique o arquivo chamado app.

Abra o console do Firebase.

Selecione seu projeto no Firebase.

Abra Desenvolvedor>>Authentication>>Configurar método de login.

Selecione e-mail/senha.

Mande ativar.

Crie uma nova Activity para ser a Main.

Selecione "Launcher" para ela ser lançada ao ligar o App e "Fragment" para termos um menu.

Remova o "Launcher" da activity Login, criada primeiro, no manifest.

Explicando MainActivity.java.

Instância de acesso ao Autenticador Firebase.

Explicando MainActivity.java.

Ao acessar o App, esta activity é acionada e o primeiro método executado é o onCreate.

Explicando MainActivity.java.

Se o usuário estiver logado mostra msg de boas vindas, senão redireciona para a activity de login.

Explicando MainActivity.java.

Esta activity possui um menu, e ao ser criado o adiciona na activity (infla ao ser clicado no canto direito superior).

Explicando MainActivity.java.

Existe uma opção no menu que é "sair". Caso ela seja selecionada, o logout é executado e o usuário é redirecionado para a activity de login.

MainActivity.java


package mobile.pitagoras.uatzap;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;

public class MainActivity extends AppCompatActivity {
    private FirebaseAuth mAuth;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mAuth = FirebaseAuth.getInstance();
        FirebaseUser user = mAuth.getCurrentUser();
        if (user != null) {
            Toast.makeText(getApplicationContext(), "Bem vindo de volta " + user.getEmail() + "!", Toast.LENGTH_LONG).show();
        } else {
            Intent intent = new Intent(this, LoginActivity.class);
            startActivity(intent);
            finish();
        }
    }
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_exit) {
            mAuth.signOut();
            startActivity(new Intent(this, LoginActivity.class));
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
					

Explicando activity_main.xml.

Utiliza um LinearLayout e possui apenas uma área para aparecer uma barra de menu.

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />
    </android.support.design.widget.AppBarLayout>
    <include layout="@layout/content_main" />
   </LinearLayout>
					

Explicando menu_main.xml.

Descreve o menu que aparece na main, com item para sair.

menu_main.xml


<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="mobile.pitagoras.uatzap.MainActivity">
    <item
        android:id="@+id/action_exit"
        android:orderInCategory="100"
        android:title="Sair"
        app:showAsAction="never" />
</menu>
					

Explicando LoginActivity.java.

Vários métodos foram criados automaticamente por termos escolhido uma activity do tipo login.

Explicando LoginActivity.java.

Para aproveitar o código já existente, vamos modificar o método attemptLogin para que ele sirva para signin ou signup, de acordo com um parâmetro passado à ele.

Explicando LoginActivity.java.

Ele passará a se chamar attemptLoginOrRegister que serve para tentar logar ou se autocadastrar. Isso depende do botão que o usuário irá clicar.

LoginActivity.java


package mobile.pitagoras.uatzap;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import java.util.ArrayList;
import java.util.List;
import static android.Manifest.permission.READ_CONTACTS;

public class LoginActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
    private FirebaseAuth mAuth;
    private static final int REQUEST_READ_CONTACTS = 0;
    private static final String[] DUMMY_CREDENTIALS = new String[]{ "foo@example.com:hello", "bar@example.com:world"};
    private UserLoginTask mAuthTask = null;
    private AutoCompleteTextView mEmailView;
    private EditText mPasswordView;
    private View mProgressView;
    private View mLoginFormView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
        populateAutoComplete();
        mPasswordView = (EditText) findViewById(R.id.password);
        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == R.id.login || id == EditorInfo.IME_NULL) {
                    attemptLoginOrRegister(false);
                    return true;
                }
                return false;
            }
        });
        mAuth = FirebaseAuth.getInstance();
        Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
        mEmailSignInButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                attemptLoginOrRegister(false);
            }
        });
        Button mSignUpButton = (Button) findViewById(R.id.email_sign_up_button);
        mSignUpButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                attemptLoginOrRegister(true);
            }
        });
        mLoginFormView = findViewById(R.id.login_form);
        mProgressView = findViewById(R.id.login_progress);
    }
    private void populateAutoComplete() {
        if (!mayRequestContacts()) {
            return;
        }
        getLoaderManager().initLoader(0, null, this);
    }
    private boolean mayRequestContacts() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true;
        }
        if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
            return true;
        }
        if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
            Snackbar.make(mEmailView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
                    .setAction(android.R.string.ok, new View.OnClickListener() {
                        @Override
                        @TargetApi(Build.VERSION_CODES.M)
                        public void onClick(View v) {
                            requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
                        }
                    });
        } else {
            requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
        }
        return false;
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults) {
        if (requestCode == REQUEST_READ_CONTACTS) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                populateAutoComplete();
            }
        }
    }
    private void attemptLoginOrRegister(boolean isNewUser) {
        if (mAuthTask != null) {
            return;
        }
        mEmailView.setError(null);
        mPasswordView.setError(null);
        String email = mEmailView.getText().toString();
        String password = mPasswordView.getText().toString();
        boolean cancel = false;
        View focusView = null;
        if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
            mPasswordView.setError(getString(R.string.error_invalid_password));
            focusView = mPasswordView;
            cancel = true;
        }
        if (TextUtils.isEmpty(email)) {
            mEmailView.setError(getString(R.string.error_field_required));
            focusView = mEmailView;
            cancel = true;
        } else if (!isEmailValid(email)) {
            mEmailView.setError(getString(R.string.error_invalid_email));
            focusView = mEmailView;
            cancel = true;
        }
        if (cancel) {
            focusView.requestFocus();
        } else {
            showProgress(true);
            if(isNewUser) {
                mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        showProgress(false);
                        Toast.makeText(getApplicationContext(), "Usuário cadastrado com sucesso. Agora você pode se autenticar com suas credenciais!", Toast.LENGTH_LONG).show();
                    }
                });
            }
            else {
                try {
                    mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) {
                            showProgress(false);
                            if (task.getResult().getUser() != null) {
                                startActivity(new Intent(LoginActivity.this, MainActivity.class));
                                finish();
                            } else {
                                Toast.makeText(getApplicationContext(), "Email e/ou senha incorretos.", Toast.LENGTH_LONG).show();
                            }
                        }
                    });
                }
                catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    private boolean isEmailValid(String email) {
        return email.contains("@");
    }
    private boolean isPasswordValid(String password) {
        return password.length() > 4;
    }
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
    private void showProgress(final boolean show) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
            mLoginFormView.animate().setDuration(shortAnimTime).alpha(
                    show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
                }
            });
            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
            mProgressView.animate().setDuration(shortAnimTime).alpha(
                    show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
                }
            });
        } else {
            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
        }
    }
    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        return new CursorLoader(this,
                Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
                        ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,
                ContactsContract.Contacts.Data.MIMETYPE +
                        " = ?", new String[]{ContactsContract.CommonDataKinds.Email
                .CONTENT_ITEM_TYPE},
                ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
    }
    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        List<String> emails = new ArrayList<>();
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            emails.add(cursor.getString(ProfileQuery.ADDRESS));
            cursor.moveToNext();
        }
        addEmailsToAutoComplete(emails);
    }
    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {    }
    private void addEmailsToAutoComplete(List<String> emailAddressCollection) {
        ArrayAdapter<String> adapter =
                new ArrayAdapter<>(LoginActivity.this,
                        android.R.layout.simple_dropdown_item_1line, emailAddressCollection);
        mEmailView.setAdapter(adapter);
    }
    private interface ProfileQuery {
        String[] PROJECTION = {
                ContactsContract.CommonDataKinds.Email.ADDRESS,
                ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
        };

        int ADDRESS = 0;
        int IS_PRIMARY = 1;
    }
    public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
        private final String mEmail;
        private final String mPassword;
        UserLoginTask(String email, String password) {
            mEmail = email;
            mPassword = password;
        }
        @Override
        protected Boolean doInBackground(Void... params) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                return false;
            }
            for (String credential : DUMMY_CREDENTIALS) {
                String[] pieces = credential.split(":");
                if (pieces[0].equals(mEmail)) {
                    return pieces[1].equals(mPassword);
                }
            }
            return true;
        }

        @Override
        protected void onPostExecute(final Boolean success) {
            mAuthTask = null;
            showProgress(false);

            if (success) {
                finish();
            } else {
                mPasswordView.setError(getString(R.string.error_incorrect_password));
                mPasswordView.requestFocus();
            }
        }

        @Override
        protected void onCancelled() {
            mAuthTask = null;
            showProgress(false);
        }
    }
}
					

Explicando activity_login.xml.

Possui um campo para e-mail e outro para senha, e dois botões, um para logar e outro pra se registrar. Ambos enviam os dados para o Firebase.

activity_login.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".LoginActivity">
    <ProgressBar
        android:id="@+id/login_progress"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:visibility="gone" />
    <ScrollView
        android:id="@+id/login_form"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:id="@+id/email_login_form"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <android.support.design.widget.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <AutoCompleteTextView
                    android:id="@+id/email"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/prompt_email"
                    android:inputType="textEmailAddress"
                    android:maxLines="1"
                    android:singleLine="true" />
            </android.support.design.widget.TextInputLayout>
            <android.support.design.widget.TextInputLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <EditText
                    android:id="@+id/password"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Senha"
                    android:imeActionId="@+id/login"
                    android:imeActionLabel="@string/action_sign_in_short"
                    android:imeOptions="actionUnspecified"
                    android:inputType="textPassword"
                    android:maxLines="1"
                    android:singleLine="true" />
            </android.support.design.widget.TextInputLayout>
            <Button
                android:id="@+id/email_sign_in_button"
                style="?android:textAppearanceSmall"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:background="@color/colorPrimaryDark"
                android:textColor="@android:color/white"
                android:text="Entrar"
                android:textStyle="bold" />
            <Button
                android:id="@+id/email_sign_up_button"
                style="?android:textAppearanceSmall"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:text="Registrar"
                android:textStyle="bold" />
        </LinearLayout>
    </ScrollView>
</LinearLayout>
				

pacotes do seu projeto

Verifique se o caminho dos pacotes estão corretos. Este código está em package mobile.pitagoras.uatzap, e deve ser trocado pelo local do seu código.

Outros arquivos

Verifique também se os seguintes arquivos estão corretos.

build.gradle (Module: app)


apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "mobile.pitagoras.uatzap"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //noinspection GradleCompatible
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.google.firebase:firebase-auth:11.6.0'
    implementation 'com.google.firebase:firebase-core:11.6.0'
    implementation 'com.google.firebase:firebase-database:11.6.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

apply plugin: 'com.google.gms.google-services'
					

build.gradle (Project: UatZap)


// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'
        

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        classpath 'com.google.gms:google-services:3.1.1'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
					

AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="mobile.pitagoras.uatzap">
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.READ_PROFILE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".LoginActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
					

Autoregistro App+Firebase

Autoregistro App+Firebase